﻿
#if UNITY_IOS || UNITY_IPHONE

using System.Collections.Generic;
using System.IO;
using HK.Core.Utils;
using HK.iOS.Editor.Data;
using HK.iOS.Editor.PostProcess.Data;
using UnityEditor;
using UnityEditor.Callbacks;
using UnityEditor.iOS.Xcode;
using UnityEngine;

namespace HK.iOS.Editor.PostProcess
{
    /// <summary>
    /// 打包Post Process
    /// </summary>
    public static class PostProcessor
    {

#if UNITY_IOS

        /// <summary>
        /// XCode工程导出时的处理
        /// </summary>
        /// <param name="iTarget">打包目标对象</param>
        /// <param name="iProjectPath">工程目录</param>
        [PostProcessBuild(900)]
        public static void OnPostProcessExportXCode(BuildTarget iTarget, string iProjectPath)
        {
            // iOS以外的场合
            if(BuildTarget.iOS != iTarget) return;
            
            var pbxProPath = PBXProject.GetPBXProjectPath(iProjectPath);
            var pbxPro = new PBXProject();
            // 读入Pbx工程
            pbxPro.ReadFromString(File.ReadAllText(pbxProPath));
            
            // 初始化Build Scheme
            InitBuildScheme(pbxPro);
            
            // Architectures
            // Xcode14以后 iOS最低支持版本已经上升到iOS11+ 所以自然而然的把无法升级到iOS11的armv7, armv7s, and i386移除了
            // 所以这里统一设定为标准的 Standard Architectures(arm64)
            var architectures = PbxBuildArchitectures.Create();
            if (!ApplyBuildItemOfString(pbxPro, (int)TargetScheme.All, architectures))
            {
                Debug.LogErrorFormat($"ApplyBuildItemOfString() Failed!(Key:{architectures.Key})");
                return;
            }
            
            // USYM_UPLOAD_AUTH_TOKEN - 为了通过打包暂时强制设置成FakeToken
            // https://forum.unity.com/threads/ios-build-is-failing-seems-like-a-fastlane-problem-not-sure-how-to-proceed.682201/#post-4701557%E4%BD%9C%E8%80%85%EF%BC%9A%E7%82%89%E7%9F%B3%E4%B8%8D%E4%BC%A0%E8%AF%B4%E9%93%BE%E6%8E%A5%EF%BC%9Ahttps://www.jianshu.com/p/a1dee00748c4%E6%9D%A5%E6%BA%90%EF%BC%9A%E7%AE%80%E4%B9%A6%E8%91%97%E4%BD%9C%E6%9D%83%E5%BD%92%E4%BD%9C%E8%80%85%E6%89%80%E6%9C%89%E3%80%82%E5%95%86%E4%B8%9A%E8%BD%AC%E8%BD%BD%E8%AF%B7%E8%81%94%E7%B3%BB%E4%BD%9C%E8%80%85%E8%8E%B7%E5%BE%97%E6%8E%88%E6%9D%83%EF%BC%8C%E9%9D%9E%E5%95%86%E4%B8%9A%E8%BD%AC%E8%BD%BD%E8%AF%B7%E6%B3%A8%E6%98%8E%E5%87%BA%E5%A4%84%E3%80%82
            var fakeToken = PbxBuildUsymUploadAuthToken.Create();
            if (!ApplyBuildItemOfString(pbxPro, (int)TargetScheme.All, fakeToken))
            {
                Debug.LogErrorFormat($"ApplyBuildItemOfString() Failed!(Key:{fakeToken.Key})");
                return;
            }
            
            // 重新Xcode Pbx工程文件
            File.WriteAllText(pbxProPath, pbxPro.WriteToString());
            
            // 重置Plist文件
            ResetPlist(iProjectPath);
        }

#region Plist

        /// <summary>
        /// 重置Plist属性
        /// </summary>
        /// <param name="iProjectPath">工程路径</param>
        private static void ResetPlist(string iProjectPath)
        {
            if (string.IsNullOrEmpty(iProjectPath))
            {
                Debug.LogError("ResetPlist():The path of xcode project is null or empty!");
                return;
            }

            if (!Directory.Exists(iProjectPath))
            {
                Debug.LogErrorFormat("ResetPlist():The path of xcode project is not exist!(Path={0})", iProjectPath);
                return;
            }
            
            var plistPath = Path.Combine(iProjectPath, "Info.plist");
            if (!File.Exists(plistPath))
            {
                Debug.LogErrorFormat("ResetPlist():The plist file is not exist!(Path={0})", plistPath);
                return;
            }
            
            var plist = new PlistDocument();
            plist.ReadFromFile(plistPath);
            
            // 用户追踪数据描述
            plist.root.SetString("NSUserTrackingUsageDescription", "雷索纳斯仅获取用于帮助游戏改善和维护的讯息，拒绝不会影响游戏的正常游玩");
            
            // 出口合格证明 - false
            plist.root.SetBoolean("ITSAppUsesNonExemptEncryption", false);

            File.WriteAllText(plistPath, plist.WriteToString());
        }

#endregion

#region Build Scheme

        /// <summary>
        /// Build Scheme列表
        /// <para>* 包含如下:</para>
        /// <para>1) Debug</para>
        /// <para>2) Release</para>
        /// <para>3) ReleaseForProfiling</para>
        /// <para>4) ReleaseForRunning</para>
        /// </summary>
        private static Dictionary<TargetScheme, IPbxBuildScheme> _buildSchemes 
            = new Dictionary<TargetScheme, IPbxBuildScheme>();

        private static void SaveBuildScheme(TargetScheme iScheme, string iTargetGuid,
            string iDebug, string iRelease, string iReleaseForProfiling,
            string iReleaseForRunning)
        {
            if (_buildSchemes.TryGetValue(iScheme, out var oSchemeInfo))
            {
                if (null == oSchemeInfo)
                {
                    oSchemeInfo = PbxBuildScheme.Create(iTargetGuid, iDebug, iRelease,
                        iReleaseForProfiling, iReleaseForRunning);
                    _buildSchemes[iScheme] = oSchemeInfo;
                }
                else
                {
                    oSchemeInfo.UpdateGuids(iDebug, iRelease, iReleaseForProfiling, iReleaseForRunning);
                }
                return;
            }
            
            oSchemeInfo = PbxBuildScheme.Create(iTargetGuid, iDebug, iRelease,
                iReleaseForProfiling, iReleaseForRunning);
            _buildSchemes.Add(iScheme, oSchemeInfo);
        }

        private static IPbxBuildScheme GetBuildScheme(TargetScheme iScheme)
        {
            if (0 >= _buildSchemes.Count) return null;
            return _buildSchemes.TryGetValue(iScheme, out var oScheme) ? oScheme : null;
        }

        /// <summary>
        /// 初始化Build Scheme
        /// </summary>
        /// <param name="iPbxPro">Pbx工程</param>
        private static void InitBuildScheme(PBXProject iPbxPro)
        {
            if(null == iPbxPro) return;
            
            // Unity-iPhone
            var targetSchemeGuid = iPbxPro.GetUnityMainTargetGuid();
            SaveTargetSchemeGuids(iPbxPro, TargetScheme.UnityIPhone, targetSchemeGuid);
            
            // UnityFramework
            targetSchemeGuid = iPbxPro.GetUnityFrameworkTargetGuid();
            SaveTargetSchemeGuids(iPbxPro, TargetScheme.UnityFramework, targetSchemeGuid);
            
            // Unity-iPhone Tests
            var unityTestTargetName = PBXProject.GetUnityTestTargetName();
            targetSchemeGuid = iPbxPro.TargetGuidByName(unityTestTargetName);
            SaveTargetSchemeGuids(iPbxPro, TargetScheme.UnityIPhoneTests, targetSchemeGuid);
            
        }

        /// <summary>
        /// 保存Target Scheme的相关Guid
        /// <para>* 包含如下:</para>
        /// <para>1) Debug</para>
        /// <para>2) Release</para>
        /// <para>3) ReleaseForProfiling</para>
        /// <para>4) ReleaseForRunning</para>
        /// </summary>
        /// <param name="iPbxPro">Pbx工程</param>
        /// <param name="iScheme">Build Scheme</param>
        /// <param name="iTargetGuid">Target Scheme的Guid</param>
        private static void SaveTargetSchemeGuids(PBXProject iPbxPro, TargetScheme iScheme, string iTargetGuid)
        {
            if(null == iPbxPro || string.IsNullOrEmpty(iTargetGuid)) return;

            var debugGuid = iPbxPro.BuildConfigByName(iTargetGuid, $"{PbxBuildConfig.Debug}");
            var releaseGuid = iPbxPro.BuildConfigByName(iTargetGuid, $"{PbxBuildConfig.Release}");
            var releaseForProfilingGuid = iPbxPro.BuildConfigByName(iTargetGuid, 
                $"{PbxBuildConfig.ReleaseForProfiling}");
            var releaseForRunningGuid = iPbxPro.BuildConfigByName(iTargetGuid, 
                $"{PbxBuildConfig.ReleaseForRunning}");
            
            // 保存
            SaveBuildScheme(iScheme, iTargetGuid, debugGuid, releaseGuid,
                releaseForProfilingGuid, releaseForRunningGuid);
        }

#endregion

#region Build Items - string

        /// <summary>
        /// 应用打包信息
        /// </summary>
        /// <param name="iPbxPro">Pbx工程</param>
        /// <param name="iScheme">打包Build Scheme</param>
        /// <param name="iBuildItem">打包信息</param>
        /// <returns>true:OK; false:NG;</returns>
        private static bool ApplyBuildItemOfString(PBXProject iPbxPro, int iScheme, 
            IPbxBuildItem<string> iBuildItem)
        {
            if(null == iPbxPro || null == iBuildItem) return false;
            
            // Unity-iPhone
            if (UtilsBytes.CheckBytes(iScheme, (int)TargetScheme.UnityIPhone))
            {
                var schemeInfo = GetBuildScheme(TargetScheme.UnityIPhone);
                if (null == schemeInfo)
                {
                    Debug.LogErrorFormat("There is no info of scheme named {0}", TargetScheme.UnityIPhone);
                    return false;
                }

                if (!ApplyBuildItemOfString(iPbxPro, schemeInfo, iBuildItem)) return false;
            }
            
            // Unity-iPhone Tests
            if (UtilsBytes.CheckBytes(iScheme, (int)TargetScheme.UnityIPhoneTests))
            {
                var schemeInfo = GetBuildScheme(TargetScheme.UnityIPhoneTests);
                if (null == schemeInfo)
                {
                    Debug.LogErrorFormat("There is no info of scheme named {0}", TargetScheme.UnityIPhoneTests);
                    return false;
                }

                if (!ApplyBuildItemOfString(iPbxPro, schemeInfo, iBuildItem)) return false;
            }
            
            // UnityFramework
            if (UtilsBytes.CheckBytes(iScheme, (int)TargetScheme.UnityFramework))
            {
                var schemeInfo = GetBuildScheme(TargetScheme.UnityFramework);
                if (null == schemeInfo)
                {
                    Debug.LogErrorFormat("There is no info of scheme named {0}", TargetScheme.UnityFramework);
                    return false;
                }

                if (!ApplyBuildItemOfString(iPbxPro, schemeInfo, iBuildItem)) return false;
            }
            
            return true;
        }

        /// <summary>
        /// 应用打包信息
        /// </summary>
        /// <param name="iPbxPro">Pbx工程</param>
        /// <param name="iSchemeInfo">打包Build Scheme信息</param>
        /// <param name="iBuildItem">打包信息</param>
        /// <returns>true:OK; false:NG;</returns>
        private static bool ApplyBuildItemOfString(PBXProject iPbxPro, 
            IPbxBuildScheme iSchemeInfo, IPbxBuildItem<string> iBuildItem)
        {
            if(null == iPbxPro || null == iSchemeInfo || null == iBuildItem) return false;

            // Debug
            iPbxPro.SetBuildPropertyForConfig(iSchemeInfo.Debug, iBuildItem.Key,
                iBuildItem.Debug);
            // Release
            iPbxPro.SetBuildPropertyForConfig(iSchemeInfo.Release, iBuildItem.Key, 
                iBuildItem.Release);
                
            // ReleaseForProfiling
            iPbxPro.SetBuildPropertyForConfig(iSchemeInfo.ReleaseForProfiling, iBuildItem.Key,
                iBuildItem.ReleaseForProfiling);
            // ReleaseForRunning
            iPbxPro.SetBuildPropertyForConfig(iSchemeInfo.ReleaseForRunning, iBuildItem.Key, 
                iBuildItem.ReleaseForRunning);
            return true;
        }

#endregion
        
#endif
        
    }
}

#endif
